home *** CD-ROM | disk | FTP | other *** search
/ Isometric Game Programming with DirectX 7.0 / Isometric Game Programming.iso / directx / dxf / samples / multimedia / directshow / misc / asfcopy / asfcopy.cpp next >
Encoding:
C/C++ Source or Header  |  2000-10-13  |  18.7 KB  |  734 lines

  1. //------------------------------------------------------------------------------
  2. // File: ASFCopy.cpp
  3. //
  4. // Desc: DirectShow sample code - ASF copy.
  5. //
  6. // Copyright (c) 1999 - 2000, Microsoft Corporation.  All rights reserved.
  7. //------------------------------------------------------------------------------
  8.  
  9.  
  10. #include <streams.h>
  11. #include <wmsdk.h>
  12. #include <atlbase.h>
  13. #include <atlimpl.cpp>
  14. #include <stdio.h>
  15.  
  16. #include <dshowasf.h>
  17.  
  18. //
  19. // Build warning to remind developers of the dependency on the 
  20. // Windows Media Format SDK libraries, which do not ship with
  21. // the DirectX SDK.
  22. //
  23. #pragma message("NOTE: To link and run this sample, you must install the Windows Media Format SDK.")
  24. #pragma message("After signing a license agreement with Microsoft, you will receive a")
  25. #pragma message("unique version of WMStub.LIB, which should be added to this VC++ project.")
  26. #pragma message("Without this library, you will receive linker errors for the following:")
  27. #pragma message("       WMCreateCertificate")
  28. #pragma message("You must also add WMVCore.LIB to the linker settings to resolve the following:")
  29. #pragma message("       WMCreateProfileManager")
  30.  
  31. // Global data
  32. BOOL fVerbose = FALSE;
  33.  
  34. // Function prototypes
  35. HRESULT MapProfileIdToProfile(int iProfile, IWMProfile **ppProfile);
  36.  
  37.  
  38.  
  39. class CKeyProvider : public IServiceProvider
  40. {
  41.     public:
  42.         //
  43.         // IUnknown interface
  44.         //
  45.         STDMETHODIMP QueryInterface(REFIID riid, void ** ppv);
  46.         STDMETHODIMP_(ULONG) AddRef();
  47.         STDMETHODIMP_(ULONG) Release();
  48.  
  49.         CKeyProvider();
  50.  
  51.         // IServiceProvider
  52.         STDMETHODIMP QueryService(REFIID siid, REFIID riid, void **ppv);
  53.  
  54.     private:
  55.         ULONG m_cRef;
  56. };
  57.  
  58. CKeyProvider::CKeyProvider() : m_cRef(0)
  59. {
  60. }
  61.  
  62. //////////////////////////////////////////////////////////////////////////
  63. //
  64. // IUnknown methods
  65. //
  66. //////////////////////////////////////////////////////////////////////////
  67.  
  68. ULONG CKeyProvider::AddRef()
  69. {
  70.     return ++m_cRef;
  71. }
  72.  
  73. ULONG CKeyProvider::Release()
  74. {
  75.     ASSERT(m_cRef > 0);
  76.  
  77.     m_cRef--;
  78.  
  79.     if(m_cRef == 0)
  80.     {
  81.         delete this;
  82.  
  83.         // don't return m_cRef, because the object doesn't exist anymore
  84.         return((ULONG) 0);
  85.     }
  86.  
  87.     return(m_cRef);
  88. }
  89.  
  90. //
  91. // QueryInterface
  92. //
  93. // We only support IUnknown and IServiceProvider
  94. //
  95. HRESULT CKeyProvider::QueryInterface(REFIID riid, void ** ppv)
  96. {
  97.     if(riid == IID_IServiceProvider || riid == IID_IUnknown)
  98.     {
  99.         *ppv = (void *) static_cast<IServiceProvider *>(this);
  100.         AddRef();
  101.         return NOERROR;
  102.     }
  103.  
  104.     return E_NOINTERFACE;
  105. }
  106.  
  107. STDMETHODIMP CKeyProvider::QueryService(REFIID siid, REFIID riid, void **ppv)
  108. {
  109.     if(siid == __uuidof(IWMReader) && riid == IID_IUnknown)
  110.     {
  111.         IUnknown *punkCert;
  112.  
  113.         HRESULT hr = WMCreateCertificate(&punkCert);
  114.  
  115.         if(SUCCEEDED(hr))
  116.             *ppv = (void *) punkCert;
  117.         else
  118.             printf("CKeyProvider::QueryService failed to create certificate!  hr=0x%x\n", hr);
  119.     
  120.         return hr;
  121.     }
  122.  
  123.     return E_NOINTERFACE;
  124. }
  125.  
  126.  
  127.  
  128. HRESULT FindPinOnFilter( IBaseFilter * pFilter, PIN_DIRECTION PinDir,
  129.                         DWORD dwPin, BOOL fConnected, IPin ** ppPin )
  130. {
  131.     HRESULT            hr = S_OK;
  132.     IEnumPins *        pEnumPin = NULL;
  133.     IPin *            pConnectedPin = NULL;
  134.     PIN_DIRECTION    PinDirection;
  135.     ULONG            ulFetched;
  136.     DWORD            nFound = 0;
  137.  
  138.     ASSERT( pFilter != NULL );
  139.     *ppPin = NULL;
  140.  
  141.     hr = pFilter->EnumPins( &pEnumPin );
  142.     if(SUCCEEDED(hr))
  143.     {
  144.         while ( S_OK == ( hr = pEnumPin->Next( 1L, ppPin, &ulFetched ) ) )
  145.         {
  146.             hr = (*ppPin)->ConnectedTo( &pConnectedPin );
  147.             if (pConnectedPin)
  148.             {
  149.                 pConnectedPin->Release();
  150.                 pConnectedPin = NULL;
  151.             }
  152.             if ( ( ( VFW_E_NOT_CONNECTED == hr ) && !fConnected ) ||
  153.                  ( ( S_OK                == hr ) &&  fConnected ) )
  154.             {
  155.                 hr = (*ppPin)->QueryDirection( &PinDirection );
  156.                 if ( ( S_OK == hr ) && ( PinDirection == PinDir ) )
  157.                 {
  158.                     if ( nFound == dwPin ) break;
  159.                     nFound++;
  160.                 }
  161.             }
  162.             (*ppPin)->Release();
  163.         }
  164.     }
  165.     pEnumPin->Release();
  166.     return hr;
  167. } // FindPinOnFilter
  168.  
  169.  
  170. HRESULT GetPin(IBaseFilter *pFilter, DWORD dwPin, IPin **ppPin)
  171. {
  172.     IEnumPins *pins;
  173.  
  174.     *ppPin = NULL;
  175.     HRESULT hr = pFilter->EnumPins(&pins);
  176.     if(FAILED(hr))
  177.     {
  178.         DbgLog((LOG_ERROR,1,TEXT("EnumPins failed!  (%x)\n"), hr));
  179.         return hr;
  180.     }
  181.  
  182.     if(dwPin > 0)
  183.     {
  184.         hr = pins->Skip(dwPin);
  185.         if(FAILED(hr))
  186.         {
  187.             DbgLog((LOG_ERROR,1,TEXT("Skip(%d) failed!  (%x)\n"), dwPin, hr));
  188.             pins->Release();
  189.             return hr;
  190.         }
  191.  
  192.         if(hr == S_FALSE)
  193.         {
  194.             DbgLog((LOG_ERROR,1,TEXT("Skip(%d) ran out of pins!\n"), dwPin));
  195.             pins->Release();
  196.             return hr;
  197.         }
  198.     }
  199.  
  200.     DWORD n;
  201.     hr = pins->Next(1, ppPin, &n);
  202.  
  203.     if(FAILED(hr))
  204.     {
  205.         DbgLog((LOG_ERROR,1,TEXT("Next() failed!  (%x)\n"), hr));
  206.     }
  207.  
  208.     if(hr == S_FALSE)
  209.     {
  210.         DbgLog((LOG_ERROR,1,TEXT("Next() ran out of pins!  \n")));
  211.         pins->Release();
  212.         return hr;
  213.     }
  214.  
  215.     pins->Release();
  216.     return hr;
  217. }
  218.  
  219.  
  220. void ListProfiles()
  221. {
  222.     USES_CONVERSION;
  223.  
  224.     int wextent = 0, Loop = 0;
  225.     DWORD cProfiles = 0;
  226.     DWORD cchName, cchDescription;
  227.     CComPtr <IWMProfileManager> pIWMProfileManager;
  228.  
  229.     printf("Standard system profiles:\n");
  230.  
  231.     HRESULT hr = WMCreateProfileManager(&pIWMProfileManager);
  232.     if(FAILED(hr))
  233.     {
  234.         printf("ListProfiles: Failed to create profile manager!  hr=0x%x\n", hr);
  235.         return; // error
  236.     }
  237.  
  238.     CComQIPtr<IWMProfileManager2, &IID_IWMProfileManager2> pIPM2(pIWMProfileManager);
  239.     if(!pIPM2) 
  240.     {
  241.         printf("ListProfiles: Failed to QI IWMProfileManager2!  hr=0x%x\n", hr);
  242.         return;
  243.     }
  244.  
  245.     // we only use 7_0 profiles
  246.     hr = pIPM2->SetSystemProfileVersion( WMT_VER_7_0 );
  247.     if(FAILED(hr)) 
  248.     {
  249.         printf("ListProfiles: Failed to set system profile version!  hr=0x%x\n", hr);
  250.         return;
  251.     }
  252.  
  253.     hr = pIWMProfileManager->GetSystemProfileCount(&cProfiles);
  254.     if(FAILED(hr))
  255.     {
  256.         printf("ListProfiles: Failed to get system profile count!  hr=0x%x\n", hr);
  257.         return;
  258.     }
  259.  
  260.     // Load the profile strings
  261.     for(int i = 0; i < (int)cProfiles; ++i)
  262.     {
  263.         CComPtr <IWMProfile> pIWMProfile;
  264.  
  265.         hr = pIWMProfileManager->LoadSystemProfile(i, &pIWMProfile);
  266.         if(FAILED(hr))
  267.         {
  268.             printf("ListProfiles: Failed to load system profile!  hr=0x%x\n", hr);
  269.             return;
  270.         }
  271.  
  272.         // How large is the profile name?
  273.         hr = pIWMProfile->GetName(NULL, &cchName);
  274.         if(FAILED(hr))
  275.         {
  276.             printf("ListProfiles: Failed to read profile name size!  hr=0x%x\n", hr);
  277.             return;
  278.         }
  279.  
  280.         WCHAR *wszProfile = new WCHAR[ cchName + 1 ];
  281.         if(NULL == wszProfile)
  282.             return;
  283.  
  284.         hr = pIWMProfile->GetName(wszProfile, &cchName);
  285.         if(FAILED(hr))
  286.         {
  287.             printf("ListProfiles: Failed to read profile name!  hr=0x%x\n", hr);
  288.             return;
  289.         }
  290.  
  291.         // How large is the description?
  292.         hr = pIWMProfile->GetDescription(NULL, &cchDescription);
  293.         if(FAILED(hr))
  294.         {
  295.             printf("ListProfiles: Failed to read profile description size!  hr=0x%x\n", hr);
  296.             return;
  297.         }
  298.  
  299.         WCHAR *wszDescription = new WCHAR[ cchDescription + 1 ];
  300.         if(NULL == wszDescription)
  301.             return;
  302.  
  303.         hr = pIWMProfile->GetDescription(wszDescription, &cchDescription);
  304.         if(FAILED(hr))
  305.         {
  306.             printf("ListProfiles: Failed to read profile description!  hr=0x%x\n", hr);
  307.             return;
  308.         }
  309.  
  310.         // Display the profile name and description
  311.         if (fVerbose)
  312.             printf("  %3d:  %ls \n[%ls]\n\n", i, wszProfile, wszDescription);
  313.         else
  314.             printf("  %3d:  %ls\n", i, wszProfile);
  315.  
  316.         delete[] wszProfile;
  317.         delete[] wszDescription;
  318.     }
  319. }
  320.  
  321.  
  322. //=======================
  323. // CreateFilterGraph
  324. //=======================
  325.  
  326. HRESULT CreateFilterGraph(IGraphBuilder **pGraph)
  327. {
  328.     HRESULT hr;
  329.  
  330.     hr = CoCreateInstance(CLSID_FilterGraph, // get the graph object
  331.         NULL,
  332.         CLSCTX_INPROC_SERVER,
  333.         IID_IGraphBuilder,
  334.         (void **) pGraph);
  335.  
  336.     if(FAILED(hr))
  337.     {
  338.         printf("CreateFilterGraph: Failed to create graph!  hr=0x%x\n", hr);
  339.         *pGraph = NULL;
  340.         return hr;
  341.     }
  342.  
  343.     return S_OK;
  344. }
  345.  
  346.  
  347. HRESULT CreateFilter(REFCLSID clsid, IBaseFilter **ppFilter)
  348. {
  349.     HRESULT hr;
  350.  
  351.     hr = CoCreateInstance(clsid,
  352.         NULL,
  353.         CLSCTX_INPROC_SERVER,
  354.         IID_IBaseFilter,
  355.         (void **) ppFilter);
  356.  
  357.     if(FAILED(hr))
  358.     {
  359.         printf("CreateFilter: Failed to create filter!  hr=0x%x\n", hr);
  360.         *ppFilter = NULL;
  361.         return hr;
  362.     }
  363.  
  364.     return S_OK;
  365. }
  366.  
  367.  
  368. HRESULT SetNoClock(IFilterGraph *graph)
  369. {
  370.     // Keep a useless clock from being instantiated....
  371.     IMediaFilter *graphF;
  372.     HRESULT hr = graph->QueryInterface(IID_IMediaFilter, (void **) &graphF);
  373.  
  374.     if(SUCCEEDED(hr))
  375.     {
  376.         hr = graphF->SetSyncSource(NULL);
  377.         if (FAILED(hr))
  378.             printf("SetNoClock: Failed to set sync source!  hr=0x%x\n", hr);
  379.  
  380.         graphF->Release();
  381.     }
  382.     else
  383.     {
  384.         printf("SetNoClock: Failed to QI for media filter!  hr=0x%x\n", hr);
  385.     }
  386.  
  387.     return hr;
  388. }
  389.  
  390.  
  391. HRESULT MapProfileIdToProfile(int iProfile, IWMProfile **ppProfile)
  392. {
  393.     DWORD cProfiles;
  394.  
  395.     *ppProfile = 0;
  396.     
  397.     CComPtr <IWMProfileManager> pIWMProfileManager;
  398.     HRESULT hr = WMCreateProfileManager( &pIWMProfileManager );
  399.     if(FAILED(hr)) 
  400.     {
  401.         printf("MapProfile: Failed to create profile manager!  hr=0x%x\n", hr);
  402.         return hr;
  403.     }
  404.  
  405.     // We only use 7_0 profiles
  406.     CComQIPtr<IWMProfileManager2, &IID_IWMProfileManager2> pIPM2(pIWMProfileManager);
  407.     if(!pIPM2) 
  408.     {
  409.         printf("MapProfile: Failed to QI IWMProfileManager2!\n");
  410.         return E_UNEXPECTED;
  411.     }
  412.  
  413.     hr = pIPM2->SetSystemProfileVersion( WMT_VER_7_0 );
  414.     if(FAILED(hr))
  415.     {
  416.         printf("MapProfile: Failed to set system profile version!  hr=0x%x\n", hr);
  417.         return hr;
  418.     }
  419.  
  420.     hr = pIWMProfileManager->GetSystemProfileCount( &cProfiles );
  421.     if(FAILED(hr))
  422.     {
  423.         printf("MapProfile: Failed to get system profile count!  hr=0x%x\n", hr);
  424.         return hr;
  425.     }
  426.  
  427.     // Invalid profile requested?
  428.     if( (DWORD)iProfile >= cProfiles ) 
  429.     {
  430.         printf("Invalid profile: %d\n", iProfile);
  431.         return E_INVALIDARG;
  432.     }
  433.  
  434.     return (pIWMProfileManager->LoadSystemProfile( iProfile, ppProfile ));
  435. }
  436.  
  437.  
  438. void WaitForCompletion( IGraphBuilder *pGraph )
  439. {
  440.     HRESULT hr;
  441.     LONG lEvCode = 0;
  442.     IMediaEvent *pEvent;
  443.  
  444.     pGraph->QueryInterface(IID_IMediaEvent, (void **) &pEvent);
  445.  
  446.     printf("Waiting for completion...\n  This could take several minutes, "
  447.            "depending on file size and selected profile.\n");
  448.     do
  449.     {
  450.         MSG Message;
  451.  
  452.         while(PeekMessage(&Message, NULL, 0, 0, TRUE))
  453.         {
  454.             TranslateMessage(&Message);
  455.             DispatchMessage(&Message);
  456.         }
  457.  
  458.         hr = pEvent->WaitForCompletion(10, &lEvCode);
  459.  
  460.     } while(lEvCode == 0);
  461.  
  462.     pEvent->Release();
  463. }
  464.  
  465.  
  466. HRESULT CopyASF(int argc, char *argv[])
  467. {
  468.     HRESULT hr;    
  469.     WCHAR SourceFile[256], TargetFile[256];
  470.     BOOL fListProfiles = TRUE;
  471.     DWORD dwProfile;
  472.     int i = 1;
  473.  
  474.     // Parse command line options
  475.     while(i < argc && (argv[i][0] == '-' || argv[i][0] == '/'))
  476.     {
  477.         // options
  478.         if(lstrcmpiA(argv[i] + 1, "v") == 0)
  479.         {
  480.             fVerbose = TRUE;
  481.             printf("Verbose mode enabled.\n");
  482.         }
  483.         else if((i+1 < argc) && lstrcmpiA(argv[i] + 1, "p") == 0)
  484.         {
  485.             fListProfiles = FALSE;
  486.             dwProfile = atoiA(argv[i+1]);
  487.             i++;  // skip two args here
  488.         } 
  489.  
  490.         i++;
  491.     }
  492.  
  493.     // List profiles only?
  494.     if(fListProfiles)
  495.     {
  496.         printf("Usage: asfcopy [/v] /p profnum file1 [ file2 ...] target\n\n");
  497.  
  498.         HRESULT hr = CoInitialize(NULL);
  499.         ListProfiles();
  500.         CoUninitialize();
  501.         return -1;
  502.     }
  503.  
  504.     // Fail with usage information if improper number of arguments
  505.     if(argc < i+2)
  506.     {
  507.         printf("Usage: asfcopy [/v] /p profnum file1 [ file2 ...] target\n");
  508.         return -1;
  509.     }
  510.  
  511.  
  512.     CComPtr <IGraphBuilder> pGraph;
  513.     CComPtr <IObjectWithSite> pObjectWithSite;
  514.     CComPtr <IBaseFilter> pMux;
  515.     CComPtr <IBaseFilter> pWriter;
  516.     CComPtr <IFileSinkFilter> pFS;
  517.     CComPtr <IConfigInterleaving> pConfigInterleaving;
  518.     CComPtr <IConfigAsfWriter> pConfigAsfWriter;
  519.     CComPtr <IMediaControl> pGraphC;
  520.  
  521.     // Convert target filename
  522.     MultiByteToWideChar(CP_ACP, 0, argv[argc - 1], -1, TargetFile, 256);
  523.  
  524.     hr = CreateFilterGraph(&pGraph);
  525.     if(FAILED(hr))
  526.     {
  527.         printf("Couldn't create filter graph! hr=0x%x", hr);
  528.         return hr;
  529.     }
  530.  
  531.     CKeyProvider prov;
  532.     prov.AddRef();  // Don't let COM try to free our static object
  533.  
  534.     // Give the graph a pointer to us for callbacks & QueryService
  535.     hr = pGraph->QueryInterface(IID_IObjectWithSite, (void**)&pObjectWithSite);
  536.     if(SUCCEEDED(hr))
  537.     {
  538.         hr = pObjectWithSite->SetSite((IUnknown *) (IServiceProvider *) &prov);
  539.         if(FAILED(hr))
  540.         {
  541.             printf("Failed to set service provider!  hr=0x%x\n", hr);
  542.             return hr;
  543.         }
  544.     }
  545.  
  546.     hr = CreateFilter(CLSID_WMAsfWriter, &pMux);
  547.     if(FAILED(hr))
  548.     {
  549.         printf("Failed to create WMAsfWriter filter!  hr=0x%x\n", hr);
  550.         return hr;
  551.     }
  552.  
  553.     hr = pMux->QueryInterface(IID_IFileSinkFilter, (void **) &pFS);
  554.     if(FAILED(hr))
  555.     {
  556.         // We need a writer also
  557.         hr = CreateFilter(CLSID_FileWriter, &pWriter);
  558.         if(FAILED(hr))
  559.         {
  560.             printf("Failed to create FileWriter filter!  hr=0x%x\n", hr);
  561.             return hr;
  562.         }
  563.         else
  564.         {
  565.             hr = pWriter->QueryInterface(IID_IFileSinkFilter, (void **) &pFS);
  566.             if(FAILED(hr))
  567.             {
  568.                 printf("Failed to create QI IFileSinkFilter!  hr=0x%x\n", hr);
  569.                 return hr;
  570.             }
  571.         }
  572.     }
  573.  
  574.     hr = pFS->SetFileName(TargetFile, NULL);
  575.     if(FAILED(hr))
  576.     {
  577.         printf("Failed to set target filename!  hr=0x%x\n", hr);
  578.         return hr;
  579.     }
  580.  
  581.     hr = pGraph->AddFilter(pMux, L"Mux");
  582.     if(FAILED(hr))
  583.     {
  584.         printf("Failed to add Mux filter to graph!  hr=0x%x\n", hr);
  585.         return hr;
  586.     }
  587.  
  588.     // Set interleaving mode to FULL
  589.     // !!! ASF won't support this, but that's okay
  590.     hr = pMux->QueryInterface(IID_IConfigInterleaving, (void **) &pConfigInterleaving);
  591.     if(SUCCEEDED(hr))
  592.     {
  593.         printf("Setting interleaving mode to INTERLEAVE_FULL\r\n");
  594.         hr = pConfigInterleaving->put_Mode(INTERLEAVE_FULL);
  595.     }
  596.  
  597.     // !!! We should only require a profile if we're using a filter which needs it
  598.     hr = pMux->QueryInterface(IID_IConfigAsfWriter, (void **) &pConfigAsfWriter);
  599.     if(SUCCEEDED(hr))
  600.     {
  601.         if (fVerbose)
  602.             printf("Setting profile to %d\r\n", dwProfile);
  603.  
  604.         CComPtr<IWMProfile> pProfile;
  605.  
  606.         hr = MapProfileIdToProfile(dwProfile, &pProfile);
  607.         if(FAILED(hr)) {
  608.             printf("Failed to map profile ID!  hr=0x%x\n", hr);
  609.             return hr;
  610.         }
  611.  
  612.         // Note that the ASF writer will not run if the number of streams
  613.         // does not match the profile.
  614.         hr = pConfigAsfWriter->ConfigureFilterUsingProfile(pProfile);
  615.         if(FAILED(hr)) {
  616.             printf("Failed to configure filter to use profile!  hr=0x%x\n", hr);
  617.             return hr;
  618.         }       
  619.     }
  620.     else
  621.     {
  622.         printf("Failed to QI for IConfigAsfWriter!  hr=0x%x\n", hr);
  623.         return hr;
  624.     }
  625.  
  626.     // Connect writer filter if needed
  627.     if(pWriter)
  628.     {
  629.         IPin *pMuxOut, *pWriterIn;
  630.         hr = pGraph->AddFilter(pWriter, L"Writer");
  631.         if(FAILED(hr))
  632.         {
  633.             printf("Failed to add FileWriter filter to graph!  hr=0x%x\n", hr);
  634.             return hr;
  635.         }
  636.  
  637.         // Look for the first unconnected output pin
  638.         hr = FindPinOnFilter(pMux, PINDIR_OUTPUT, 0, FALSE, &pMuxOut);
  639.         if(FAILED(hr))
  640.         {
  641.             printf("Failed to find output pin on Mux!  hr=0x%x\n", hr);
  642.             return hr;
  643.         }
  644.         // Find the first connected pin
  645.         hr = FindPinOnFilter(pWriter, PINDIR_INPUT, 0, FALSE, &pWriterIn);
  646.         if(FAILED(hr))
  647.         {
  648.             printf("Failed to find input pin on FileWriter!  hr=0x%x\n", hr);
  649.             pMuxOut->Release();
  650.             return hr;
  651.         }
  652.  
  653.         hr = pGraph->ConnectDirect(pMuxOut, pWriterIn, NULL);
  654.         pMuxOut->Release(); 
  655.         pWriterIn->Release();
  656.         if(FAILED(hr))
  657.         {
  658.             printf("Failed to connect Mux to FileWriter!  hr=0x%x\n", hr);
  659.             return hr;
  660.         }
  661.  
  662.         if(fVerbose)
  663.             printf("Connected Mux and writer, hr = 0x%x\n", hr);
  664.     }
  665.  
  666.     // Set sync source to NULL to speed processing
  667.     SetNoClock(pGraph);
  668.  
  669.     // Render all source files listed on the command line
  670.     while(i < argc - 1)
  671.     {
  672.         MultiByteToWideChar(CP_ACP, 0, argv[i], -1,
  673.             SourceFile, 256);
  674.  
  675.         printf("Copying %ls to %ls\n", SourceFile, TargetFile);
  676.  
  677.         hr = pGraph->RenderFile(SourceFile, NULL);
  678.         if(FAILED(hr))
  679.             printf("Failed to render source file %s!  hr=0x%x\n", argv[i], hr);
  680.         else if (fVerbose)
  681.             printf("RenderFile('%ls') returned hr=0x%x\n", SourceFile, hr);
  682.  
  683.         ++i;
  684.     }
  685.  
  686.     // Run the graph
  687.     hr = pGraph->QueryInterface(IID_IMediaControl, (void **) &pGraphC);
  688.     if(FAILED(hr))
  689.     {
  690.         printf("Failed to QI for IMediaControl!  hr=0x%x\n", hr);
  691.         return hr;
  692.     }
  693.  
  694.     hr = pGraphC->Run();
  695.     if(FAILED(hr))
  696.     {
  697.         printf("Failed to run the graph!  hr=0x%x\nCopy aborted.\n\n", hr);
  698.         printf("Please check that you have selected the correct profile for copying.\n"
  699.                "Note that if your source ASF file is audio-only, then selecting a\n"
  700.                "video profile will cause a failure when running the graph.\n\n");
  701.         ListProfiles();
  702.     }
  703.     else
  704.     {
  705.         WaitForCompletion(pGraph);
  706.         printf("Copy complete.\n");
  707.  
  708.         // Stop the graph
  709.         hr = pGraphC->Stop();
  710.     }
  711.  
  712.     return hr;
  713. }
  714.  
  715.  
  716. int __cdecl
  717. main(
  718.     int argc,
  719.     char *argv[]
  720.     )
  721. {
  722.     // Initialize COM
  723.     HRESULT hr = CoInitialize(NULL);
  724.  
  725.     // Since COM smart pointers are used, the main functionality is wrapped
  726.     // in CopyASF().  When the function returns, the smart pointers will clean
  727.     // up properly, and then we'll uninitialize COM.
  728.     hr = CopyASF(argc, argv);
  729.  
  730.     CoUninitialize();
  731.     return hr;
  732. }
  733.  
  734.